package com.github.linkoog.model_designer.ide.editer.dbmodel.right_editer;

import com.github.linkoog.model_designer.ide.editer.common.ColumnVo;
import com.github.linkoog.model_designer.ide.editer.dbmodel.DBModelConstants;
import com.github.linkoog.model_designer.utils.YamlReadUtil;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.SearchTextField;
import com.intellij.util.ui.JBDimension;
import org.jetbrains.yaml.YAMLElementGenerator;
import org.jetbrains.yaml.psi.*;

import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;

public class DBModelRightPanel implements Disposable, DumbAware {




    private final Project project;
    private final FileEditor fileEditor;
    private final VirtualFile virtualFile;
    private final YAMLFile yamlFile;
    private final YAMLElementGenerator yamlElementGenerator;

    private JPanel myMainPanel;
    private JPanel commonContainerPanel;
    private JPanel datasourcesContainerPanel;
    private JPanel commonColumnsContainerPanel;

    private JPanel tableContainerPanel;
    private JPanel tableSearchPanel;
    private SearchTextField tableSearchField;
    private JPanel tableContextPanel;

    private final DatasourceListBuilder datasourceListBuilder;
    private final CommonColumnListBuilder commonColumnListBuilder;
    private final TableListPanelBuilder tableListPanelBuilder;



    public DBModelRightPanel(Project project, FileEditor fileEditor, VirtualFile virtualFile){
        this.project = project;
        this.fileEditor = fileEditor;
        this.virtualFile = virtualFile;
        this.virtualFile.putUserData(DBModelConstants.DB_MODEL_RIGHT_PANEL_KEY, this);
        this.yamlFile = (YAMLFile) PsiManager.getInstance(project).findFile(virtualFile);
        this.yamlElementGenerator = YAMLElementGenerator.getInstance(project);

        this.datasourceListBuilder = new DatasourceListBuilder(project, virtualFile);
        this.commonColumnListBuilder = new CommonColumnListBuilder(project, virtualFile);
        this.tableListPanelBuilder = new TableListPanelBuilder(project, virtualFile);


        datasourceListBuilder.setCallback(() -> {
            commonColumnListBuilder.getCommonColumnJTable().clearSelection();
            tableListPanelBuilder.getDbtableInfoJTable().clearSelection();
        });

        commonColumnListBuilder.setCallback(() -> {
            datasourceListBuilder.getDatasourceJTable().clearSelection();
            tableListPanelBuilder.getDbtableInfoJTable().clearSelection();
        });

        tableListPanelBuilder.setCallback(() -> {
            datasourceListBuilder.getDatasourceJTable().clearSelection();
            commonColumnListBuilder.getCommonColumnJTable().clearSelection();
        });

        initPanelUI();
        initYamlFileds();
        resetPanelContext();
    }

    private void initPanelUI(){
        myMainPanel.setMinimumSize(new JBDimension(70, -1));
        datasourcesContainerPanel.setBorder(new TitledBorder(new LineBorder(Color.LIGHT_GRAY),"数据源") );
        commonColumnsContainerPanel.setBorder(new TitledBorder(new LineBorder(Color.LIGHT_GRAY),"通用列") );
        tableContainerPanel.setBorder(new TitledBorder(new LineBorder(Color.LIGHT_GRAY),"数据库表"));

        initDatasourceListPanel();
        initCommonColumnListPanel();
        initTableListPanel();
    }

    private void initDatasourceListPanel(){
        datasourcesContainerPanel.add(datasourceListBuilder.getMyMainPanel(), BorderLayout.CENTER);
    }

    private void initCommonColumnListPanel(){
        commonColumnsContainerPanel.add(commonColumnListBuilder.getMyMainPanel(), BorderLayout.CENTER);
    }

    private void initTableSearchPanel(){
        this.tableSearchField = new SearchTextField(true) {
            private Timer instantSearchTimer;
            private int instantSearchDelay = 350;

            @Override
            protected boolean preprocessEventForTextField(KeyEvent e) {
                if ((KeyEvent.VK_ENTER == e.getKeyCode()) || ('\n' == e.getKeyChar())) {
                    addCurrentTextToHistory();
                    postActionEvent();
                    e.consume();
                } else {
                    getInstantSearchTimer().restart();
                }
                return super.preprocessEventForTextField(e);
            }

            @Override
            protected void onFocusLost() {
                tableSearchField.addCurrentTextToHistory();
                postActionEvent();
            }

            @Override
            protected void onFieldCleared() {
                postActionEvent();
            }

            public Timer getInstantSearchTimer() {
                if (this.instantSearchTimer == null) {
                    this.instantSearchTimer = new Timer(instantSearchDelay, new ActionListener() {
                        public void actionPerformed(ActionEvent e) {
                            postActionEvent();
                        }
                    });
                    this.instantSearchTimer.setRepeats(false);
                }

                return this.instantSearchTimer;
            }

            public void postActionEvent() {
                this.getInstantSearchTimer().stop();
                doFilterTable();
            }

            public int getInstantSearchDelay() {
                return this.instantSearchDelay;
            }

            public void setInstantSearchDelay(int instantSearchDelay) {
                this.firePropertyChange("instantSearchDelay", this.instantSearchDelay, this.instantSearchDelay = instantSearchDelay);
            }
        };
        this.tableSearchPanel.add(tableSearchField, BorderLayout.CENTER);
    }

    private void doFilterTable(){
        String searchText = tableSearchField.getText();
        tableListPanelBuilder.filterTable(searchText);
    }

    private void initTableListPanel(){
        initTableSearchPanel();
        tableContextPanel.add(tableListPanelBuilder.getMyMainPanel(),BorderLayout.CENTER);
    }

    private void initYamlFileds(){
        final YAMLDocument root = yamlFile.getDocuments().get(0);
        assert root != null;

        final Application application = ApplicationManager.getApplication();
        application.invokeLater(() -> {
            WriteCommandAction.runWriteCommandAction(project, () -> {
                YAMLMapping rootMapping = PsiTreeUtil.findChildOfType(root, YAMLMapping.class);
                if (rootMapping == null) {
                    final YAMLFile yamlFile = YAMLElementGenerator.getInstance(project).createDummyYamlWithText(DBModelConstants.DATASOURCES + ":\n" + DBModelConstants.COMMON_COLUMNS + ":\n");
                    final YAMLMapping mapping = (YAMLMapping) yamlFile.getDocuments().get(0).getTopLevelValue();
                    assert mapping != null;
                    rootMapping = ((YAMLMapping)root.add(mapping));
                }else {
                    YAMLKeyValue nameKeyValue = rootMapping.getKeyValueByKey(DBModelConstants.DATASOURCES);
                    if (nameKeyValue == null){
                        nameKeyValue = (YAMLKeyValue)rootMapping.addBefore(yamlElementGenerator.createYamlKeyValue(DBModelConstants.DATASOURCES, ""), rootMapping.getFirstChild());
                    }

                    YAMLKeyValue commentKeyValue = rootMapping.getKeyValueByKey(DBModelConstants.COMMON_COLUMNS);
                    if (commentKeyValue == null){
                        PsiElement element = rootMapping.addAfter(yamlElementGenerator.createEol(), nameKeyValue);
                        commentKeyValue = (YAMLKeyValue)rootMapping.addAfter(yamlElementGenerator.createYamlKeyValue(DBModelConstants.COMMON_COLUMNS, ""), element);
                    }

                    //为table配置的columns下，自定义列补全属性
                    for (YAMLKeyValue yamlKeyValue : rootMapping.getKeyValues()) {
                        final String keyText = yamlKeyValue.getKeyText();
                        if (DBModelConstants.DATASOURCES.equals(keyText)  || DBModelConstants.COMMON_COLUMNS.equals(keyText)){
                            continue;
                        }

                        // table节点
                        final YAMLValue value = yamlKeyValue.getValue();
                        if (!(value instanceof YAMLMapping)){
                            continue;
                        }

                        YAMLMapping mapping = (YAMLMapping)value;
                        YAMLKeyValue columnsKeyValue = mapping.getKeyValueByKey("columns");
                        if (columnsKeyValue == null ||  columnsKeyValue.getValue() == null ||  !(columnsKeyValue.getValue() instanceof YAMLMapping)){
                            continue;
                        }

                        YAMLMapping columnsMapping = (YAMLMapping)columnsKeyValue.getValue();
                        for (YAMLKeyValue keyValue : columnsMapping.getKeyValues()) {
                            YAMLValue columnValue = keyValue.getValue();
                            if (!(columnValue instanceof YAMLMapping)){
                                continue;
                            }

                            YAMLMapping columnMapping = (YAMLMapping)columnValue;
                            ColumnVo.defaultAttributeMap.forEach((key, val) -> {
                                YAMLKeyValue attrKeyValue = columnMapping.getKeyValueByKey(key);
                                if (attrKeyValue == null){
                                    columnMapping.putKeyValue(yamlElementGenerator.createYamlKeyValue(key, val));
                                }
                            });
                        }
                    }
                }
            });
        });
    }

    private void cacheCommonColumns(){
        Map<String, ColumnVo> comcolMap = new HashMap<>();
        final YAMLDocument root = yamlFile.getDocuments().get(0);
        if (root == null) {
            this.virtualFile.putUserData(DBModelConstants.DB_MODEL_COMMOM_COLUMNS_KEY, comcolMap);
            return;
        }

        YAMLMapping rootMapping = PsiTreeUtil.findChildOfType(root, YAMLMapping.class);
        if (rootMapping == null) {
            this.virtualFile.putUserData(DBModelConstants.DB_MODEL_COMMOM_COLUMNS_KEY, comcolMap);
            return;
        }

        YAMLKeyValue comcolKeyValue = rootMapping.getKeyValueByKey(DBModelConstants.COMMON_COLUMNS);
        if (comcolKeyValue != null && comcolKeyValue.getValue() != null && comcolKeyValue.getValue() instanceof YAMLMapping){
            YAMLMapping comcolMapping = (YAMLMapping)comcolKeyValue.getValue();
            for (YAMLKeyValue keyValue : comcolMapping.getKeyValues()) {
                ColumnVo columnVo = YamlReadUtil.readColumn(keyValue);
                comcolMap.put(keyValue.getKeyText(), columnVo);
            }
        }
        this.virtualFile.putUserData(DBModelConstants.DB_MODEL_COMMOM_COLUMNS_KEY, comcolMap);

    }

    public void resetDatasourceList(){
        datasourceListBuilder.resetDatasourceList();
    }

    public void resetCommonColumnList(){
        commonColumnListBuilder.resetCommonColumnList();
    }

    public void resetTableList(){
        tableListPanelBuilder.resetTableList();
    }

    public void resetPanelContext() {
        cacheCommonColumns();
        resetDatasourceList();
        resetCommonColumnList();
        resetTableList();
    }


    public JPanel getMyMainPanel() {
        return myMainPanel;
    }

    @Override
    public void dispose() {

    }


}
